package model

import (
	"context"
	"log"
	"net"
	"os"
	"os/signal"
	"sync/atomic"
	"syscall"
	"time"
)

type Server struct {
	Ctx         context.Context
	Cancel      context.CancelFunc
	Listener    net.Listener
	ActiveConns int64 // 原子计数器，当前活跃连接数
}

func (s *Server) HandleConnection(conn net.Conn) {
	defer func() {
		conn.Close()
		atomic.AddInt64(&s.ActiveConns, -1)
	}()

	// 1. 设置读超时，用于心跳和空闲连接断开
	_ = conn.SetReadDeadline(time.Now().Add(90 * time.Second))

	// 2. （可选）初始化会话数据，记录到外部存储如Redis
	// sessionID := generateID()
	// redisClient.Set(sessionKey(sessionID), conn.RemoteAddr().String(), 90*time.Second)

	// 3. 读循环
	buf := make([]byte, 4096) // 每个连接独立的缓冲区，大小根据协议调整
	for {
		select {
		case <-s.Ctx.Done():
			return
		default:
		}

		n, err := conn.Read(buf)
		if err != nil {
			// 超时错误，心跳超时，关闭连接
			if netErr, ok := err.(net.Error); ok && netErr.Timeout() {
				log.Println("Connection timed out")
				return
			}
			// 其他错误，如客户端断开
			return
		}

		// 收到任何数据，重置读超时时间，保活连接
		_ = conn.SetReadDeadline(time.Now().Add(90 * time.Second))

		// 处理数据：这里绝对不能阻塞！
		// 将消息投递到Channel，由后台Worker池处理
		message := make([]byte, n)
		copy(message, buf[:n])             // 拷贝数据，避免共享buf带来的数据竞争
		go s.processMessage(conn, message) // 简单示例，生产环境应用channel和worker pool
	}
}

func (s *Server) processMessage(conn net.Conn, data []byte) {
	// 业务逻辑
	// 例如：解析协议、验证权限、发往Kafka等
	// response := handleBusinessLogic(data)
	// conn.Write(response)
}

func (s *Server) Monitor() {
	ticker := time.NewTicker(5 * time.Second)
	defer ticker.Stop()
	for {
		select {
		case <-ticker.C:
			conns := atomic.LoadInt64(&s.ActiveConns)
			log.Printf("Current active connections: %d", conns)
		case <-s.Ctx.Done():
			return
		}
	}
}

func (s *Server) HandleShutdown() {
	sigCh := make(chan os.Signal, 1)
	signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM)
	<-sigCh
	log.Println("Received shutdown signal")

	s.Cancel()         // 通知所有handleConnection循环退出
	s.Listener.Close() // 停止Accept新连接

	// 等待所有连接自然超时或处理完毕
	time.Sleep(95 * time.Second) // 等待时间 > 读超时时间
	log.Println("Server exited gracefully")
	os.Exit(0)
}
